import logging
import os

from django.core.exceptions import ObjectDoesNotExist
from django.db import DataError
from django.db.models import ProtectedError
from djcelery.models import PeriodicTask

from UiManager.models import ProjectInfo, PageInfo, ElementInfo, LocationInfo, TestSuiteInfo, \
    EnvInfo, ResourceInfo, TestCaseInfo, TestStepInfo, OprationInfo, LogInfo, ReportInfo, SystemSettings

logger = logging.getLogger('Alpaca')


def operation_project_data(type, **kwargs):
    """
    项目信息落地
    :param kwargs: dict
    :return: success or tips
    """
    project_opt = ProjectInfo.objects
    project_name = kwargs.get('project_name')
    if type == 'add':
        if project_opt.get_project_name(project_name) < 1:
            try:
                project_opt.insert_project(**kwargs)
            except DataError:
                return '项目信息过长'
            except Exception:
                logging.error('项目添加异常：{kwargs}'.format(kwargs=kwargs))
                return '添加失败，请重试'
            logger.info('项目添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该项目已存在，请重新编辑'
    elif type == "edit_save":
        project_id = kwargs.pop('id')
        if project_name != project_opt.get_project_name_by_project_id(project_id=project_id) \
                and project_opt.get_project_name(project_name) >= 1:
            return '该项目已存在，请重新命名'
        try:
            project_opt.update_project(project_id, **kwargs)
        except DataError:
            return '项目信息过长'
        except Exception:
            logging.error('更新失败：{kwargs}'.format(kwargs=kwargs))
            return '更新失败，请重试'
        logger.info('项目更新成功：{kwargs}'.format(kwargs=kwargs))
    elif type == "delete":
        id = kwargs.pop('id', None)
        try:
            ProjectInfo.objects.get(id=id).delete()
        except ProtectedError:
            return '项目下有存在资源，不可删除'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_page_data(type, **kwargs):
    """
    页面信息落地
    :param kwargs: dict
    :return: success or tips
    """
    page_opt = PageInfo.objects
    project_opt = ProjectInfo.objects
    page_name = kwargs.get('page_name')
    if type == "add":
        project_name = kwargs.get('belong_project')
        project_obj = project_opt.get_project_obj_by_project_name(project_name)
        kwargs['belong_project'] = project_obj
        if page_opt.get_page_name(page_name) < 1:
            try:
                page_opt.insert_page(**kwargs)
            except DataError:
                return '页面信息过长'
            except Exception as e:
                logging.error('页面添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('页面添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该页面已存在，请重新编辑'
    elif type == "edit_save":
        page_id = kwargs.pop('id')
        if page_name != page_opt.get_page_name_by_page_id(page_id=page_id) \
                and page_opt.get_page_name(page_name) >= 1:
            return '该页面已存在，请重新命名'
        try:
            page_opt.update_page(page_id, **kwargs)
        except DataError:
            return '页面信息过长'
        except Exception:
            logging.error('更新失败：{kwargs}'.format(kwargs=kwargs))
            return '更新失败，请重试'
        logger.info('页面更新成功：{kwargs}'.format(kwargs=kwargs))
    elif type == "delete":
        id = kwargs.pop('id', None)
        try:
            PageInfo.objects.get(id=id).delete()
        except ProtectedError:
            return '页面下有存在资源，不可删除'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_element_data(type, **kwargs):
    """
    页面信息落地
    :param kwargs: dict
    :return: success or tips
    """
    # 获取page_id
    page_id = kwargs.get('belong_page')

    # 获取location_id
    location_id = kwargs.get('belong_location')

    # 获取element_id
    element_value = kwargs.get('element_value')

    # 判断是否插入数据重复
    element_opt = ElementInfo.objects

    count = element_opt.get_element_obj_count(page_id, element_value, location_id)
    if type == 'add':

        if count < 1:
            location_opt = LocationInfo.objects
            location_obj = location_opt.get_location_obj_by_location_id(location_id)
            page_opt = PageInfo.objects
            page_obj = page_opt.get(id=page_id)
            kwargs['belong_location'] = location_obj
            kwargs['belong_page'] = page_obj
            try:
                element_opt.insert_element(**kwargs)
            except DataError:
                return '元素信息过长'
            except Exception as e:
                logging.error('元素添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('元素添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该元素已存在，请重新编辑'
    elif type == "edit_save":
        element_id = kwargs.pop('id')
        ele_obj = element_opt.get_element_obj_by_element_id(element_id=element_id)
        if (page_id != ele_obj.belong_page_id
            or element_value != ele_obj.element_value
            or location_id != ele_obj.belong_location_id) \
                and count >= 1:
            return '该元素名称已存在，请重新命名'
        try:
            element_opt.update_element(element_id, **kwargs)
        except DataError:
            return '元素信息过长'
        except Exception:
            logging.error('更新失败：{kwargs}'.format(kwargs=kwargs))
            return '更新失败，请重试'
        logger.info('元素更新成功：{kwargs}'.format(kwargs=kwargs))
    elif type == "delete":
        id = kwargs.pop('id', None)
        steps = TestStepInfo.objects.filter(belong_element_id=id).values('id')
        case_steps = TestCaseInfo.objects.values('steps')
        if steps and case_steps:
            for step in steps:
                for case_step in case_steps:
                    case_step = case_step['steps'].split(',')
                    if str(step['id']) in case_step:
                        return '有正在使用该元素的用例，请在用例中删除使用该元素的步骤，然后在进行删除操作'

        try:
            TestStepInfo.objects.filter(belong_element_id=id).delete()
            ElementInfo.objects.get(id=id).delete()
        except ProtectedError:
            return '有正在使用该元素的用例，请在用例中删除使用该元素的步骤，然后在进行删除操作 002'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_case_data(type, **kwargs):
    """
    用例信息落地
    :param kwargs: dict
    :return: success or tips
    """
    steps = kwargs.pop('steps', None)

    step_opt = TestStepInfo.objects

    case_id = kwargs.pop('id', None)

    # 临时list
    temp = []

    if steps:
        for step in steps:
            try:
                operation_opt = OprationInfo.objects
                operation_name = step.get('operation_name')
                operation_id = operation_opt.get_id_by_opration_name(opration_name=operation_name)
            except:
                return '操作选项不能为空'

            input_data = step.get('input_data', None)
            element_id = step.get('element_id', None)
            step_must = step.get('step_must', None)

            count = step_opt.get_step_obj_count(input_data=input_data, belong_element_id=element_id, belong_opration_id=operation_id, step_must=step_must)

            if count > 0:
                step_id = step_opt.get_id_obj_step(input_data=input_data, belong_element_id=element_id, belong_opration_id=operation_id, step_must=step_must)
            else:
                # 插入step表
                try:
                    step_opt.insert_step(input_data=input_data, belong_element_id=element_id, belong_opration_id=operation_id, step_must=step_must)
                except:
                    return '插入步骤出错，请联系开发人员解决。'
                step_id = step_opt.get_id_obj_step(input_data=input_data,
                                                   belong_element_id=element_id, belong_opration_id=operation_id, step_must=step_must)

            temp.append(str(step_id))

        kwargs['steps'] = ','.join(temp)
        # 判断是否插入数据重复
        case_name = kwargs.get('case_name', None)
        case_opt = TestCaseInfo.objects
        count = case_opt.get_case_obj_count(case_name=case_name)

    if type == 'add':
        if count < 1:
            try:
                case_opt.insert_case(**kwargs)
            except DataError:
                return '用例信息过长'
            except Exception as e:
                logging.error('用例添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('用例添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该用例名称已存在，请重新编辑'
    elif type == 'edit_save':
        if case_name != case_opt.get(id=case_id).case_name and count >= 1:
            return '该用例名称已存在，请重新编辑'
        else:
            try:
                case_opt.update_case(id=case_id, **kwargs)
            except DataError:
                return '用例信息过长'
            except Exception as e:
                logging.error('用例添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('用例添加成功：{kwargs}'.format(kwargs=kwargs))
    elif type == "delete":
        # 套件用例id集合
        cases = TestSuiteInfo.objects.values('cases')
        if cases:
            for case in cases:
                case = case['cases'].split(',')
                if str(case_id) in case:
                    return '有正在使用该用例的套件，请在套件中删除此用例，然后在进行删除操作'

        try:
            TestCaseInfo.objects.get(id=case_id).delete()
        except ProtectedError:
            return '有正在使用该用例的套件，请在套件中删除此用例，然后在进行删除操作 002'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=case_id))
    return 'success'


def operation_suite_data(type, **kwargs):
    """
    套件信息落地
    :param kwargs: dict
    :return: success or tips
    """
    suite_name = kwargs.get('suite_name')
    project_id = kwargs.pop('project', None)
    if project_id:
        project_obt = ProjectInfo.objects
        project_obj = project_obt.get_project_obj_by_project_id(project_id)
        kwargs['belong_project'] = project_obj
        kwargs['status'] = 'False'
        # 处理cases
        kwargs['cases'] = ','.join(kwargs['cases'])

        # 判断是否插入数据重复
        suite_opt = TestSuiteInfo.objects
        count = suite_opt.get_suite_obj_count(suite_name=suite_name)
    if type == 'add':
        if count < 1:
            try:
                suite_opt.insert_suite(**kwargs)
            except DataError:
                return '套件信息过长'
            except Exception as e:
                logging.error('套件添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('套件添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该套件名称已存在，请重新编辑'
    elif type == 'edit_save':
        suite_id = kwargs.pop('id', None)
        if count >= 1 and suite_name != suite_opt.get(id=suite_id).suite_name:
            return '该套件名称已存在，请重新编辑'
        else:
            try:
                suite_opt.update_suite(suite_id, **kwargs)
            except DataError:
                return '套件信息过长'
            except Exception as e:
                logging.error('套件添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('套件添加成功：{kwargs}'.format(kwargs=kwargs))
    elif type == "delete":
        id = kwargs.pop('id', None)
        kwargs = PeriodicTask.objects.values('kwargs')

        for arg in kwargs:
            tmp_list = eval(arg['kwargs'])
            if tmp_list and tmp_list.get('env', None):
                if str(id) == tmp_list['suite']:
                    return "该套件在定时任务中，请先删除定时任务"
        try:
            LogInfo.objects.filter(belong_suite_id=id).delete()
            TestSuiteInfo.objects.get(id=id).delete()
        except ProtectedError:
            return '套件下有存在资源，不可删除'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_env_data(type, **kwargs):
    """
    环境信息落地
    :param kwargs: dict
    :return: success or tips
    """

    env_name = kwargs.get('env_name', None)
    if env_name:
        system_opt = SystemSettings.objects.get(id=1)
        app_package = kwargs.pop('appPackage', None)
        app_activity = kwargs.pop('appActivity', None)
        app = system_opt.resource_dir + '/' + kwargs.pop('resource_name', None)
        capabilities = {
            'app': app,
            'appPackage': app_package,
            'appActivity': app_activity,
            'unicodeKeyboard': True,
            'resetKeyboard': True,
            'newCommandTimeout': 240,
            'platformName': 'android',
            'version': '6.0',
            'deviceName': ''
        }

        kwargs['capabilities'] = str(capabilities)

        if kwargs.get('rule') == '请选择':
            kwargs['rule'] = ''

        # 判断是否插入数据重复
        env_opt = EnvInfo.objects
        count = env_opt.get_env_obj_count(env_name=env_name)

    if type == 'add':
        if count < 1:
            try:
                env_opt.insert_env(**kwargs)
            except DataError:
                return '环境信息过长'
            except Exception as e:
                logging.error('环境添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('环境添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该环境名称已存在，请重新编辑'
    elif type == 'edit_save':
        id = kwargs.pop('id')
        if count >= 1 and env_name != env_opt.get(id=id).env_name:
            return '该环境名称已存在，请重新编辑'
        else:
            try:
                env_opt.update_env(id, **kwargs)
            except DataError:
                return '环境信息过长'
            except Exception as e:
                logging.error('环境添加异常：{kwargs}'.format(kwargs=kwargs))
                print(e)
                return '添加失败，请重试'
            logger.info('环境添加成功：{kwargs}'.format(kwargs=kwargs))

    elif type == "delete":
        id = kwargs.pop('id', None)
        kwargs = PeriodicTask.objects.values('kwargs')

        for arg in kwargs:
            tmp_list = eval(arg['kwargs'])
            if tmp_list and tmp_list.get('env', None):
                if str(id) == tmp_list['env']:
                    return "有正在使用该环境的定时任务，请先删除定时任务"
        try:
            LogInfo.objects.filter(belong_suite_id=id).delete()
            EnvInfo.objects.get(id=id).delete()
        except ProtectedError:
            return '环境下有存在资源，不可删除'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_resource_data(type, **kwargs):
    """
    resource信息落地
    :param kwargs: dict
    :return: success or tips
    """
    system_opt = SystemSettings.objects.get(id=1)
    resource_opt = ResourceInfo.objects
    resource_file = kwargs.pop('resource', None)
    if type == 'add':
        if not resource_file:
            return '文件不存在'
        kwargs['resource_name'] = resource_file.name
        count = resource_opt.get_resource_obj_count(resource_file.name)
        # 判断是否插入数据重复
        if count < 1:
            try:
                resource_opt.insert_resource(**kwargs)
                # 打开特定的文件进行二进制的写操作
                destination = open(os.path.join(system_opt.resource_dir, resource_file.name), 'wb+')
                for chunk in resource_file.chunks():  # 分块写入文件
                    destination.write(chunk)
                destination.close()
            except DataError:
                return '文件资源信息过长'
            except Exception as e:
                logging.error('resource添加异常：{kwargs}'.format(kwargs=kwargs))
                return '添加失败，请重试' + str(e)
            logger.info('resource添加成功：{kwargs}'.format(kwargs=kwargs))
        else:
            return '该resource文件名称已存在，请重新上传'

    elif type == 'edit_save':
        id = kwargs.pop('id', None)
        resource_opt.update_resource(id, **kwargs)

    elif type == 'delete':
        id = kwargs.pop('id', None)
        resource_name = ResourceInfo.objects.get(id=id).resource_name
        capabilities = EnvInfo.objects.values('capabilities')

        for arg in capabilities:
            tmp_list = eval(arg['capabilities'])
            if resource_name == tmp_list['app'].split('/')[-1]:
                return "有正在使用该资源的环境，请先删除环境"
        try:
            resource_obj = resource_opt.get(id=id)
            resource_name = resource_obj.resource_name
            resource_obj.delete()
            resource_file = os.path.join(system_opt.resource_dir, resource_name)
            if os.path.exists(resource_file):
                os.remove(resource_file)
        except ProtectedError:
            return '有正在使用该资源的模块，不可删除'
        except ObjectDoesNotExist:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_report_data(type, **kwargs):
    """
    report信息落地
    :param kwargs: dict
    :return: success or tips
    """
    id = kwargs.pop('id', None)
    if type == 'delete':
        try:
            report_opt = ReportInfo.objects.get(id=id)
            run_suite = report_opt.html_report_name
            start_at = report_opt.start_at
            report_opt.delete()
            report_dir = os.path.join(os.getcwd(), 'templates', 'reports', run_suite) + '-' + str(start_at) + '.html'
            if os.path.exists(report_dir):
                os.remove(report_dir)
        except Exception:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_log_data(type, **kwargs):
    """
    log信息落地
    :param kwargs: dict
    :return: success or tips
    """
    id = kwargs.pop('id', None)
    if type == 'delete':
        try:
            log_opt = LogInfo.objects.get(id=id)
            log_name = log_opt.log_name
            log_opt.delete()

            system_opt = SystemSettings.objects.get(id=1)
            log_dir = system_opt.log_dir

            log_dir = log_dir + '/' + str(log_name) + '.log'
            logging.info('日志地址：' + log_dir)
            if os.path.exists(log_dir):
                os.remove(log_dir)

        except Exception:
            return '删除异常，请重试'
        logging.info('{id} 模块已删除'.format(id=id))
    return 'success'


def operation_system_data(**kwargs):
    """
    系统设置信息落地
    :param kwargs: dict
    :return: success or tips
    """
    system_opt = SystemSettings.objects

    try:
        if system_opt.count() == 1:
            system_opt.update_system(**kwargs)
        else:
            system_opt.insert_system(**kwargs)
    except DataError:
        return '系统信息过长'
    except Exception as e:
        logging.error('系统设置添加异常：{kwargs}'.format(kwargs=kwargs))
        print(e)
        return '添加失败，请重试'
    logger.info('系统设置添加成功：{kwargs}'.format(kwargs=kwargs))

    return 'success'
